﻿using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;

namespace YBOT_Field_Control
{
    public class Game
    {
        #region Game and Scoring Variables

        OneWire g1w;                        //One Wire constructor
        XBee gXB;                           //Xbee Constructor
        Field_Control gFC;                  //Field Control Constructor
        LogWriter gLW = new LogWriter();    //Log Writer Constructor
        Time gTime = new Time();            //Time Constructor

        private string time =                //Time of day stamp
              DateTime.Now.Hour.ToString() + "_"
            + DateTime.Now.Minute.ToString() + "_"
            + DateTime.Now.Second.ToString();


        public TeamVariables red = new TeamVariables();            //New team 
        public TeamVariables green = new TeamVariables();        //New team

        public int autoModeTime = 20;   //Autonomous Mode time in secs
        public int midModeTime = 120;    //Mid Mode time + automode time
        public int matchNumber = 0;     //Current match number


        //Game flags
        public bool gameDone = false;       //True when game has finished
        public bool STOP = false;           //True when game has been stopped
        public bool autoMode = false;       //True when game is in autonomous mode
        public bool midMode = false;        //True when game is in middle game mode
        public bool endMode = false;        //True when game is in end of game mode
        public bool practiceMode = false;   //True when game is in practice mode

        //------------------------------------------------------------------------------------------------\\
        //Current year's game variables
        //------------------------------------------------------------------------------------------------\\

        private int autoballValue = 5;
        private int autoMax = 4;
        public bool useLatch = true;

        #endregion

        #region Constructors

        public Game()
        {
            this.g1w = new OneWire();
            this.gXB = new XBee();
            this.gFC = new Field_Control();
        }

        public Game(OneWire _g1w)
        {
            this.g1w = _g1w;
        }

        public Game(XBee _gXB)
        {
            this.gXB = _gXB;
        }

        public Game(Field_Control _gFC)
        {
            this.gFC = _gFC;
        }

        public Game(OneWire _g1w, XBee _gXB)
        {
            this.g1w = _g1w;
            this.gXB = _gXB;
        }

        public Game(OneWire _g1w, XBee _gXB, Field_Control _gFC)
        {
            this.g1w = _g1w;
            this.gXB = _gXB;
            this.gFC = _gFC;
        }

        #endregion

        //Initiate game class
        public void begin()
        {
            this.red.reset();                        //Reset Red variables
            this.green.reset();                      //Reset Green variables

            midMode = false;                    //Reset midGame flag
            endMode = false;                    //Reset endGame flag

            STOP = false;                       //Reset STOP flag
            gameDone = false;                   //Reset gameDone flag
        }

        /// <summary>
        /// Start a new game
        /// </summary>
        public void GameStartUp()
        {
            begin();        //reset variables and flags       
            this.gFC.StartUp();  //Start up field communications

            practiceMode = false;
            autoMode = true;

            GameLog("Game Started");

            //Ring Bell
            this.gFC.RingBell();

            //Turn on All Field Lights
            this.gFC.AllLights(true);

            //Turn off All Field Lights
            this.gFC.AllLights(false);

            //Reset latch status of each tower//
            this.gFC.AllTowersLatchReset();          
            GameLog("All Tower Latch Reset"); 

            //Turn on Robot Transmiters
            this.gFC.RobotTransmitters(true, true);
            GameLog("Transmitters On");

            GameLog("Game Start");

        }

        /// <summary>
        /// Start a new game
        /// </summary>
        public void GameStartUp(bool _autoMode, bool _practiceMode)
        {
            begin();
            this.gFC.StartUp();
            STOP = false;
            gameDone = false;
            autoMode = _autoMode;
            practiceMode = _practiceMode;

            GameLog("**********************************************************");
            GameLog("Match #" + matchNumber.ToString());
            GameLog("Game Started");

            //Ring Bell
            this.gFC.RingBell();

            //Turn on All Field Lights
            this.gFC.AllLights(true);

            //Turn off All Field Lights
            this.gFC.AllLights(false);

            GameLog("Transmitters On");

            GameLog("Game Start");

            //If practice mode
            if (practiceMode && _autoMode)
            {
                //Turn on Robot Transmiters
                this.gFC.RobotTransmitters(_autoMode, true);
            }
            else if (practiceMode)
            {
                //Turn on Robot Transmiters
                this.gFC.RobotTransmitters(false, true);
            }
            else
            {
                //Something to do here?
            }

        }

        /// <summary>
        /// End a Game
        /// </summary>
        public void GameShutDown()
        {
            //Turn off Transmitters
            this.gFC.RobotTransmitters(false, false);

            //Sound buzzer
            this.gFC.SoundBuzzer();

            GameLog("Towers Off");
            GameLog("Game End");
        }

        /// <summary>
        /// Main Game control :  enters and exits game modes
        /// </summary>
        public void MainGame()
        {

            //Do loop until the game is over or stopped
            while (!STOP && !gameDone)
            {
                //Game Flow code here
                if (!practiceMode)
                {
                    //If Automode enter AutoMode
                    if (autoMode && !midMode && !endMode) AutoMode();

                    //Do this between rounds
                    else if (autoMode && midMode && !endMode)
                    {
                        this.gFC.RobotTransmitters(false, true);    //Turn on transmitter to Manual Mode
                        this.gFC.RingBell();                        //Ring bell
                        autoMode = false;                           //Set auto flag
                        GameLog("AutoMode Over");                   //Update Log
                        GameLog("Transmitters ON");                 //Update Log
                        this.gFC.AllLights(false);                  //Turn off all Lights
                        this.gFC.AllTowersLatchReset();             //Rest Latches
                        GameLog("All Towers' Latch Reset");         //Update log

                        //Turn on lights
                        this.gFC.Light(3, (int)pin.red, true);
                        this.gFC.Light(4, (int)pin.red, true);
                        this.gFC.Light(5, (int)pin.red, true);
                        this.gFC.Light(6, (int)pin.red, true);
                        GameLog("Towers 3, 4, 5, & 6 Lit Red");
                        this.gFC.Light(7, (int)pin.green, true);
                        this.gFC.Light(8, (int)pin.green, true);
                        this.gFC.Light(1, (int)pin.green, true);
                        this.gFC.Light(2, (int)pin.green, true);
                        GameLog("Towers 7, 8, 1, & 2 Lit Green");
                    }

                    //If not autoMode and not Endmode enter MidMode
                    else if (!autoMode && midMode && !endMode) MidMode();

                    //Not needed this year
                    //else if (!autoMode && midMode && endMode)
                    //{
                    //    this.gFC.AllLights(true);
                    //    this.gFC.RingBell();
                    //    midMode = false;
                    //    GameLog("MidMode Over");
                    //    this.gFC.AllLights(false);
                    //}
                    //else if (!autoMode && !midMode && endMode) EndMode();
                }
                else
                {
                    //Place Practice Mode code here
                }

                Application.DoEvents();         //Do window's stuff
                return;                         //Return to control program
            }
        }

        public void AutoMode()
        {
            //Read Latch State of towers
            this.gFC.ReadState(3, useLatch);
            this.gFC.ReadState(7, useLatch);
            //Check Latch status
            this.red.scored = this.gFC.PinRead(3, (int)pin.input1, useLatch);
            this.green.scored = this.gFC.PinRead(7, (int)pin.input1, useLatch);

            //If Red Scored and hasn't finished
            if (this.red.scored && !this.red.autoFinished)
            {
 
                //Increase ball count
                this.red.autoBall++;
                //Score ball
                this.red.autoScore = (autoballValue * this.red.autoBall);
                //Update score
                this.red.score = this.red.autoScore;
                GameLog("Red Scored: Red Count = " + this.red.autoBall);
                GameLog("            Red Score = " + this.red.score);

                //Light the appropriate tower
                if (this.red.autoBall == 1) this.gFC.Light(8, (int)pin.red, true);
                else if (this.red.autoBall == 2) this.gFC.Light(1, (int)pin.red, true);
                else if (this.red.autoBall == 3) this.gFC.Light(2, (int)pin.red, true);
                //If this is the last scorable ball
                else if (this.red.autoBall == 4)
                {
                    //Light last tower and finish AutoMode for this team
                    this.gFC.Light(3, (int)pin.red, true);
                    this.red.autoBonus = true;
                    this.red.autoFinished = true;
                    this.red.score = this.red.score + this.red.autoBonusValue;
                    GameLog("Red AutoBonus: Red Score = " + this.red.score);
                }

                //Clear Latches on this tower
                if (useLatch) this.gFC.LatchReset(3);
                this.red.scored = false;
                GameLog("            Red Latch Reset");
            }

            //If Green Scored and hasn't finished
            if (this.green.scored && !this.green.autoFinished)
            {
                //Increase ball count
                this.green.autoBall++;
                //Score ball
                this.green.autoScore = (autoballValue * this.green.autoBall);
                //Update score
                this.green.score = this.green.autoScore;
                GameLog("Green Scored: Green Count = " + this.green.autoBall);
                GameLog("              Green Score = " + this.green.score);

                //Light the appropriate tower
                if (this.green.autoBall == 1) this.gFC.Light(4, (int)pin.green, true);
                else if (this.green.autoBall == 2) this.gFC.Light(5, (int)pin.green, true);
                else if (this.green.autoBall == 3) this.gFC.Light(6, (int)pin.green, true);
                //If this is the last scorable ball
                else if (this.green.autoBall == 4)
                {
                    //Light last tower and finish AutoMode for this team
                    this.gFC.Light(7, (int)pin.green, true);
                    this.green.autoBonus = true;
                    this.green.autoFinished = true;
                    this.green.score = this.green.score + this.green.autoBonusValue;
                    GameLog("Green AutoBonus: Green Score = " + this.green.score);
                }

                //Clear Latches on this tower
                if (useLatch) this.gFC.LatchReset(7);
                this.green.scored = false;
                GameLog("              Green Latch Reset");
            }
        }

        public void MidMode()
        {
            byte _state;
            //Check each tower to see if a ball has been passed
            FlipFlop(1);
            FlipFlop(3);
            FlipFlop(5);
            FlipFlop(7);

            //If corner towers match light corner tower that color 
            //Else turn it out
            if (CornerCheck(1,3, out _state)) 
            {
                if (this.gFC.nodeState[2].state == 0x00)
                {
                    this.gFC.WriteNodeState(2, _state);
                    GameLog("Towers 1&3 Match: Change state to " + _state);
                }
            }
            else if(this.gFC.nodeState[2].state != 0x00)
            {
                this.gFC.WriteNodeState(2, _state);
                GameLog("Towers 1&3 DON'T Match: Change state to " + _state);
            }

            if (CornerCheck(5, 3, out _state))
            {
                if (this.gFC.nodeState[4].state == 0x00)
                {
                    this.gFC.WriteNodeState(4, _state);
                    GameLog("Towers 5&3 Match: Change state to " + _state);
                }
            }
            else if (this.gFC.nodeState[4].state != 0x00)
            {
                this.gFC.WriteNodeState(4, _state);
                GameLog("Towers 5&3 DON'T Match: Change state to " + _state);
            }

            if (CornerCheck(5, 7, out _state))
            {
                if (this.gFC.nodeState[6].state == 0x00)
                {
                    this.gFC.WriteNodeState(6, _state);
                    GameLog("Towers 5&7 Match: Change state to " + _state);
                }
            }
            else if (this.gFC.nodeState[6].state != 0x00)
            {
                this.gFC.WriteNodeState(6, _state);
                GameLog("Towers 5&7 DON'T Match: Change state to " + _state);
            }

            if (CornerCheck(1, 7, out _state))
            {
                if (this.gFC.nodeState[8].state == 0x00)
                {
                    this.gFC.WriteNodeState(8, _state);
                    GameLog("Towers 7&1 Match: Change state to " + _state);
                }
            }
            else if (this.gFC.nodeState[8].state != 0x00)
            {
                this.gFC.WriteNodeState(8, _state);
                GameLog("Towers 7&1 DON'T Match: Change state to " + _state);
            }

        }

        public void EndMode()
        {
            //Not used this year
        }


        /// <summary>
        /// Writes text to log file
        /// </summary>
        /// <param name="text">Text as string</param>
        public void GameLog(string text)
        {
            string file = "\\Match " + matchNumber.ToString() + " - Log";
            string folder = "Matches\\" + "Match " + matchNumber.ToString();

            this.gLW.WriteLog(text, file, folder);
        }

        //------------------------------------------------------------------------------------------------\\
        //Current year's game methods
        //------------------------------------------------------------------------------------------------\\


        /// <summary>
        /// Used to Flip the tower color to the other team's color
        /// </summary>
        /// <param name="_towerNum">Tower Number</param>
        public void FlipFlop(int _towerNum)
        {
            //Get the state of given tower
            this.gFC.ReadState(_towerNum, useLatch);
            //if (useLatch) this.gFC.ReadState(_towerNum);

            //Check the latch state of the input
            bool _input = this.gFC.PinRead(_towerNum, (int)pin.input1, useLatch);

            //If there was an input
            if (_input)
            {
                //If the tower was red 
                if (this.gFC.PinRead(_towerNum, (int)pin.red))
                {
                    //Change it to green
                    this.gFC.Light(_towerNum, false, true, false, false);
                    GameLog("Tower #" + _towerNum + " Flipped to Green"); 
                }
                else
                {
                    //It must have been green so change it to red
                    this.gFC.Light(_towerNum, true, false, false, false);
                    GameLog("Tower #" + _towerNum + " Flipped to Red");
                }
                //Clear latch on given tower
                if (useLatch) this.gFC.LatchReset(_towerNum);
            }
        }

        /// <summary>
        /// Used to check to see if two towers match
        /// </summary>
        /// <param name="_tower1">1st tower</param>
        /// <param name="_tower2">2nd tower</param>
        /// <returns>match and state of corner tower</returns>
        private bool CornerCheck(int _tower1, int _tower2, out byte cornerState)
        {
            //If both towers are red
            if (this.gFC.PinRead(_tower1, (int)pin.red) && this.gFC.PinRead(_tower2, (int)pin.red))
            {
                //Match and corner tower is red
                cornerState = (byte)pin.redOnlyByte;
                return true;                   
            }
            else if (this.gFC.PinRead(_tower1, (int)pin.green) && this.gFC.PinRead(_tower2, (int)pin.green))
            {
                //Match and corner tower is green
                cornerState = (byte)pin.greenOnlyByte;
                return true;                   
            }
            else
            {
                //No Match and corner tower is off
                cornerState = (byte)pin.allOffByte;
                return false;
            }
        }


    }
}
